package com.huiquan.inspection.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.huiquan.analysis.domain.User;
import com.huiquan.framework.base.BaseService;
import com.huiquan.framework.base.ReturnCode;
import com.huiquan.framework.base.ReturnData;
import com.huiquan.framework.utils.GetListUtil;
import com.huiquan.framework.utils.ReturnUtil;
import com.huiquan.inspection.constants.InspectionConstant;
import com.huiquan.inspection.dao.TestingClassDao;
import com.huiquan.inspection.domain.TestingClass;

@Service
public class TestingClassService extends BaseService {

	@Autowired
	private TestingClassDao testingClassDao;

	/**
	 * 获取检验大类列表
	 * 
	 * @param startStr
	 * @param keyword
	 * @param exactSearchFlag 
	 * @return
	 */
	public Map<String, Object> getList(String startStr, String keyword, String countPerPageStr, String exactSearchFlag) {
		int start = startStr == null ? 1 : Integer.parseInt(startStr);
		boolean exactFlag = exactSearchFlag != null && exactSearchFlag.equals("1");

		Map<String, Object> param = new HashMap<>();
		if (keyword != null && !keyword.isEmpty()) {
			param.put("keyword", exactFlag ? keyword : "%" + keyword + "%");
		}
		int totalSize = testingClassDao.retrieveSize(param);

		Map<String, Integer> pageNo = new HashMap<>();
		if (countPerPageStr != null && !countPerPageStr.isEmpty()) {
			int countPerPage = Integer.parseInt(countPerPageStr);
			pageNo = GetListUtil.getPageNoParam(totalSize, start + "", countPerPage);
			param.put("countPerPage", countPerPage);
		} else {
			pageNo = GetListUtil.getPageNoParam(totalSize, start + "");
		}
		int endPage = pageNo.get("endPage");
		start = pageNo.get("start");
		int startIndex = pageNo.get("startIndex");

		List<TestingClass> list = new ArrayList<>();

		if (startIndex < totalSize) {
			param.put("startIndex", startIndex);
			list = testingClassDao.retrieveList(param);
		}

		Map<String, String> showSearch = new LinkedHashMap<>();
		showSearch.put("keyword", "名称");
		
		Map<String, Object> map = GetListUtil.getReturnMap2(totalSize, start, startIndex, endPage, list, null);
		map.put("showSearch", showSearch);
		return map;
	}

	/** 上传图片保存路径 */
	@Value("${inspection.testing.class.image.path}")
	private String uploadImagePath;

	/**
	 * 插入一个检验大类
	 * 
	 * @param params
	 * @param user
	 * @param image
	 * @return
	 * @throws IllegalStateException
	 * @throws IOException
	 */
	public ReturnData insert(Map<String, String> params, User user, MultipartFile image)
			throws IllegalStateException, IOException {
		int count = testingClassDao.retrieveSizeByName(params.get("name"), null);
		if (count > 0) {
			return ReturnUtil.fail(ReturnCode.TESTING_CLASS_NAME_EXIST);
		}
		String imageName = image.getOriginalFilename();
		// 上传文件并获得文件URL
		String imageURL = uploadImage(image, imageName);
		// 插入到mysql
		createClass(params, imageName, imageURL, user);

		return ReturnUtil.success();
	}

	/**
	 * 批量插入检验大类
	 * 
	 * @param user
	 * @param zipFile
	 * @return
	 * @throws IOException
	 */
	public ReturnData batchAddTestingClass(User user, MultipartFile zipFile) throws IOException {
		File file = File.createTempFile("tempZip", ".zip");
		zipFile.transferTo(file);
		ZipFile zf = new ZipFile(file);
		ZipEntry ze = null;
		String fileName = null;
		InputStream in = null;
		Enumeration<ZipEntry> em = zf.getEntries();
		while (em.hasMoreElements()) {
			ze = em.nextElement();
			// 如果当前条目是目录，报错
			if (ze.isDirectory()) {
				zf.close();
				return ReturnUtil.fail(ReturnCode.IMPORT_ZIP_DIRECTORY_ERROR);
			}
			fileName = ze.getName();
			if (fileName.endsWith(".png") || fileName.endsWith(".PNG")) {
				in = zf.getInputStream(ze);
				decompressionPng(in, fileName, uploadImagePath);
			} else if (fileName.endsWith(".txt") || fileName.endsWith(".TXT")) {
				in = zf.getInputStream(ze);
				readMapperAndCreatClass(in, user);
			}
		}
		zf.close();
		return ReturnUtil.success();
	}

	/**
	 * 更新一个大类的图片
	 * 
	 * @param id
	 * @param user
	 * @param image
	 * @return
	 * @throws IllegalStateException
	 * @throws IOException
	 */
	public ReturnData updateImage(String id, User user, MultipartFile image) throws IllegalStateException, IOException {
		TestingClass tc = testingClassDao.retrieveObjectById(Long.parseLong(id));
		String imageName = image.getOriginalFilename();
		String path = uploadImagePath + imageName;
		File file = new File(path);
		// 更新或覆盖原图片
		image.transferTo(file);
		// 如果新图片名和原图片名不同，要更新图片名和URL
		String oldImageName = tc.getImageName();
		if (!imageName.equals(oldImageName)) {
			tc.setImageName(imageName);
			tc.setImageURL(tc.getImageURL().replace(oldImageName, imageName));
			tc.setModifierId(user.getUserId());
			tc.setModifierName(user.getRealName());
			testingClassDao.update(tc);
		}
		return ReturnUtil.success();
	}

	/**
	 * 更新一个大类的disable
	 * 
	 * @param id
	 * @param user
	 * @param disable
	 * @return
	 */
	public ReturnData updateDisable(String id, User user, String disable) {
		TestingClass tc = testingClassDao.retrieveObjectById(Long.parseLong(id));
		tc.setDisable(Integer.valueOf(disable));
		tc.setModifierId(user.getUserId());
		tc.setModifierName(user.getRealName());
		testingClassDao.update(tc);
		return ReturnUtil.success();
	}

	/**
	 * 移动检验大类的位置，调整其排序
	 * 
	 * @param user
	 * @param id
	 * @param flag
	 *            移动标识:0-上移，1-下移
	 * @return
	 */
	public ReturnData move(User user, String id, int flag) {
		TestingClass tc = testingClassDao.retrieveObjectById(Long.parseLong(id));
		TestingClass temp = null;
		if (flag == 0) {
			temp = testingClassDao.selectFirstHighByRank(tc.getRank());
			if (temp == null) {
				return ReturnUtil.fail(ReturnCode.TESTING_CLASS_MOVE_HIGHEST_ERROR);
			}
		} else {
			temp = testingClassDao.selectFirstLowByRank(tc.getRank());
			if (temp == null) {
				return ReturnUtil.fail(ReturnCode.TESTING_CLASS_MOVE_LOWEST_ERROR);
			}
		}
		int tempRank = temp.getRank();
		temp.setRank(tc.getRank());
		temp.setModifierId(user.getUserId());
		temp.setModifierName(user.getRealName());
		testingClassDao.update(temp);
		tc.setRank(tempRank);
		tc.setModifierId(user.getUserId());
		tc.setModifierName(user.getRealName());
		testingClassDao.update(tc);
		return ReturnUtil.success();
	}

	/**
	 * 上传图片到服务器
	 * 
	 * @param image
	 *            图片文件流
	 * @param imageName
	 *            图片名
	 * @return
	 * @throws IOException
	 * @throws IllegalStateException
	 */
	private String uploadImage(MultipartFile image, String imageName) throws IllegalStateException, IOException {
		String path = uploadImagePath + imageName;
		File file = new File(path);
		image.transferTo(file);
		return InspectionConstant.FICTITIOUS_IMAGE_PATH + imageName;
	}

	/**
	 * 创建一个TestingClass并插入到MySql
	 * 
	 * @param params
	 * @param imageName
	 * @param imageURL
	 * @param user
	 * @return
	 */
	public Long createClass(Map<String, String> params, String imageName, String imageURL, User user) {

		TestingClass tc = new TestingClass();

		tc.setId(Long.valueOf(params.get("id")));
		tc.setName(params.get("name"));
		tc.setRank(Integer.valueOf(params.get("rank")));
		tc.setDisable(Integer.valueOf(params.get("disable")));
		tc.setImageName(imageName);
		tc.setImageURL(imageURL);
		tc.setModifierId(user.getUserId());
		tc.setModifierName(user.getRealName());

		return testingClassDao.insert(tc);
	}

	public Long createClass(String name, String imageName, String imageURL, User user) {

		TestingClass tc = new TestingClass();

		tc.setName(name);
		tc.setImageName(imageName);
		tc.setImageURL(imageURL);
		tc.setModifierId(user.getUserId());
		tc.setModifierName(user.getRealName());

		return testingClassDao.insert(tc);
	}

	/**
	 * 删除一个TestingClass
	 * 
	 * @param id
	 */
	public void deleteClass(String id) {
		TestingClass tc = new TestingClass();
		tc.setId(Long.valueOf(id));
		testingClassDao.delete(tc);
	}

	public List<TestingClass> getAll() {
		Map<String, Object> param = new HashMap<>();
		param.put("all", "1");
		return testingClassDao.retrieveList(param);
	}

	public ReturnData update(String id, String name, String imageName, User user) {
		TestingClass tc = testingClassDao.retrieveObjectById(Long.parseLong(id));

		if (StringUtils.isNotEmpty(name)) {
			int count = testingClassDao.retrieveSizeByName(name, Long.parseLong(id));
			if (count > 0) {
				return ReturnUtil.fail(ReturnCode.TESTING_CLASS_NAME_EXIST);
			}
			tc.setName(name);
		}
		if (StringUtils.isNotEmpty(imageName)) {
			// 更新服务器上的文件名
			renameFile(uploadImagePath, tc.getImageName(), imageName);
			String imageURL = tc.getImageURL();
			imageURL = imageURL.replace(tc.getImageName(), imageName);
			tc.setImageURL(imageURL);
			tc.setImageName(imageName);
		}

		tc.setModifierId(user.getUserId());
		tc.setModifierName(user.getRealName());
		testingClassDao.update(tc);

		return ReturnUtil.success();
	}

	/**
	 * 服务器文件重命名
	 * 
	 * @param path
	 * @param oldname
	 * @param newname
	 */
	private void renameFile(String path, String oldname, String newname) {
		if (!oldname.equals(newname)) {// 新的文件名和以前文件名不同时,才有必要进行重命名
			File oldfile = new File(path + "/" + oldname);
			File newfile = new File(path + "/" + newname);
			if (!oldfile.exists()) {
				// 重命名文件不存在
				LOGGER.info("文件不存在");
				return;
			}
			if (newfile.exists())// 若在该目录下已经有一个文件和新文件名相同，则不允许重命名
				LOGGER.info(newname + "已经存在！");
			else {
				oldfile.renameTo(newfile);
			}
		} else {
			LOGGER.info("新文件名和旧文件名相同");
		}
	}

	/**
	 * 解压出PNG图片
	 * 
	 * @param in
	 * @param fileName
	 * @param decompressionPath
	 * @throws IOException
	 */
	private void decompressionPng(InputStream in, String fileName, String decompressionPath) throws IOException {
		byte[] buf = new byte[1024];
		int len = 0;
		OutputStream ot = new FileOutputStream(decompressionPath + fileName);
		while ((len = in.read(buf)) != -1) {
			ot.write(buf, 0, len);
		}
		ot.flush();
		ot.close();
		in.close();
	}

	/**
	 * 读取映射文件并创建检验大类对象写入到数据库
	 * 
	 * @param in
	 * @param user
	 * @throws IOException
	 */
	private void readMapperAndCreatClass(InputStream in, User user) throws IOException {
		InputStreamReader read = new InputStreamReader(in, "UTF-8"); // 考虑到文本编码
		BufferedReader bf = new BufferedReader(read);
		String line = null;
		String s[] = null;
		Map<String, String> params = null;
		while ((line = bf.readLine()) != null) {
			s = line.split("\t");
			if (s.length == 5) {
				params = new HashMap<>();
				params.put("name", s[0]);
				params.put("id", s[2]);
				params.put("rank", s[3]);
				params.put("disable", s[4]);
				createClass(params, s[1], InspectionConstant.FICTITIOUS_IMAGE_PATH + s[1], user);
			}

		}
		read.close();
	}

}
